﻿using System.Collections.Generic;
using System.Threading.Tasks;

namespace Odyssey.Consul.Implementations
{
    using Features;
    using Http;
    using Models;

    internal class ACLs : BaseConsulAPI, IACLs
    {
        public ACLs(IHttpRequester httpRequester, IConsulConfiguration consulConfiguration) : base(httpRequester, consulConfiguration, EnumResource.ACL)
        {
        }

        private string BuildAclPath(string action = "")
        {
            return BuildUri("acl", action);
        }
        public async Task<ResultBootstrap> Bootstrap()
        {
            return await ApiSend<ResultBootstrap>(BuildAclPath("bootstrap"), EnumConsulHttpMethod.Put);
        }

        public async Task<ResultReplication> Replication(QueryParameter queryParameter)
        {
            return await ApiSend<ResultReplication>(BuildAclPath("replication"), queryParameter: queryParameter);
        }

        public async Task<ResultLogin> Login(ArguLogin arguLogin)
        {
            return await ApiSend<ArguLogin, ResultLogin>(BuildAclPath("login"), arguLogin, EnumConsulHttpMethod.Post);
        }

        public async Task Logout(string token)
        {
            await ApiSendResponse(BuildAclPath("logout"), EnumConsulHttpMethod.Post, requestHeaders: BuildTokenHeader());
        }

        #region token

        private string BuildTokenPath(string action)
        {
            return BuildAclPath($"token/{action}");
        }

        private string BuildTokenPath()
        {
            return BuildAclPath("token");
        }

        public async Task<ResultToken> TokenCreate(ArguToken arguToken)
        {
            return await ApiSend<ArguToken, ResultToken>(BuildTokenPath(), arguToken, requestHeaders: BuildTokenHeader());
        }

        public async Task<ResultToken> TokenRead(string accessorID)
        {
            return await ApiSend<ResultToken>(BuildTokenPath(accessorID), requestHeaders: BuildTokenHeader());
        }

        public async Task<ResultToken> TokenReadSelf(string token)
        {
            return await ApiSend<ResultToken>(BuildTokenPath("self"), requestHeaders: BuildTokenHeader(token));
        }

        public async Task<ResultToken> TokenUpdate(ArguToken arguToken)
        {
            return await ApiSend<ArguToken, ResultToken>(BuildTokenPath(arguToken.AccessorID), arguToken, requestHeaders: BuildTokenHeader());
        }

        public async Task<ResultToken> TokenClone(ArguToken arguToken)
        {
            var path = BuildTokenPath($"{arguToken.AccessorID}/clone");
            return await ApiSend<ArguToken, ResultToken>(path, arguToken, requestHeaders: BuildTokenHeader());
        }

        public async Task<bool> TokenDelete(string accessorID)
        {
            return (await ApiSendString(BuildTokenPath(accessorID), requestHeaders: BuildTokenHeader())).Contains("true");
        }

        public async Task<List<ResultToken>> TokenList()
        {
            var path = "acl/tokens";
            return await ApiSend<List<ResultToken>>(path, requestHeaders: BuildTokenHeader());
        }

        #endregion

        #region Policy

        private string BuildPoliyPath()
        {
            return BuildAclPath($"policy");
        }

        private string BuildPoliyPath(string action)
        {
            return BuildAclPath($"policy/{action}");
        }

        public async Task<ResultPolicy> PolicyCreate(ArguPolicy arguPolicy)
        {
            return await ApiSend<ArguPolicy, ResultPolicy>(BuildPoliyPath(), arguPolicy, requestHeaders: BuildTokenHeader());
        }

        public async Task<ResultPolicy> PolicyRead(string id)
        {
            return await ApiSend<ResultPolicy>(BuildPoliyPath(id), requestHeaders: BuildTokenHeader());
        }

        public async Task<ResultPolicy> PolicyUpdate(ArguPolicy arguPolicy)
        {
            return await ApiSend<ArguPolicy, ResultPolicy>(BuildPoliyPath(arguPolicy.ID), arguPolicy, requestHeaders: BuildTokenHeader());
        }

        public async Task<bool> PolicyDelete(string id)
        {
            return (await ApiSendString(BuildPoliyPath(id), requestHeaders: BuildTokenHeader())).Contains("true");
        }

        public async Task<List<ResultPolicy>> PolicyList()
        {
            return await ApiSend<List<ResultPolicy>>(BuildAclPath("policies"), requestHeaders: BuildTokenHeader());
        }
        #endregion

        #region Role
        private string BuildRolePath(string action)
        {
            return BuildAclPath($"acl/{action}");
        }
        public async Task<ResultRole> RoleCreate(ArguRole arguRole)
        {
            return await ApiSend<ArguRole, ResultRole>(BuildRolePath(arguRole.ID), arguRole);
        }

        public async Task<ResultRole> RoleRead(string id, string name)
        {
            var path = string.Empty;
            if (string.IsNullOrWhiteSpace(id))
            {
                path = BuildRolePath($"name/{name}");
            }
            else
            {
                path = BuildRolePath(id);
            }

            return await ApiSend<ResultRole>(path);
        }

        public async Task<ResultRole> RoleUpdate(ArguRole arguRole)
        {
            return await ApiSend<ArguRole, ResultRole>(BuildRolePath(arguRole.ID), arguRole);
        }

        public async Task<bool> RoleDelete(string id)
        {
            return (await ApiSendString(BuildRolePath(id))).Contains("true");
        }

        public async Task<List<ResultRole>> RoleList()
        {
            return await ApiSend<List<ResultRole>>(BuildRolePath("roles"));
        }
        #endregion

        #region Auth-Method

        private string BuildAuthMethodPath()
        {
            return BuildAclPath($"auth-method");
        }

        private string BuildAuthMethodPath(string action)
        {
            return BuildAclPath($"auth-method/{action}");
        }
        public async Task<ResultAuthMethod> AuthMehotdCreate(ArguAuthMethod arguAuthMethod)
        {
            return await ApiSend<ArguAuthMethod, ResultAuthMethod>(BuildAuthMethodPath(), arguAuthMethod);
        }

        public async Task<ResultAuthMethod> AuthMethodRead(string name)
        {
            return await ApiSend<ResultAuthMethod>(BuildAuthMethodPath(name));
        }

        public async Task<ResultAuthMethod> AuthMethodUpdate(ArguAuthMethod arguAuthMethod)
        {
            return await ApiSend<ArguAuthMethod, ResultAuthMethod>(BuildAuthMethodPath(arguAuthMethod.Name), arguAuthMethod);
        }

        public async Task<bool> AuthMethodDelete(string name)
        {
            return (await ApiSendString(BuildAuthMethodPath(name))).Contains("true");
        }

        public async Task<List<ResultAuthMethod>> AuthMethodList()
        {
            var path = BuildAclPath("auth-methods");
            return await ApiSend<List<ResultAuthMethod>>(path);
        }
        #endregion

        #region Binding Rule
        private string BuildBindingRulePath()
        {
            return BuildAclPath("binding-rule");
        }

        private string BuildBindingRulePath(string id)
        {
            return BuildAclPath($"binding-rule/{id}");
        }
        public async Task<ResultBindingRule> BindingRuleCreate(ArguBindingRule arguBindingRule)
        {
            return await ApiSend<ArguBindingRule, ResultBindingRule>(BuildBindingRulePath(), arguBindingRule);
        }

        public async Task<ResultBindingRule> BindingRuleRead(string id)
        {
            return await ApiSend<ResultBindingRule>(BuildBindingRulePath(id));
        }

        public async Task<ResultBindingRule> BindingRuleUpdate(ArguBindingRule arguBindingRule)
        {
            return await ApiSend<ArguBindingRule, ResultBindingRule>(BuildBindingRulePath(arguBindingRule.ID), arguBindingRule);
        }

        public async Task<bool> BindingRuleDelete(string id)
        {
            return (await ApiSendString(BuildBindingRulePath(id))).Contains("true");
        }

        public async Task<List<ResultBindingRule>> BindingRuleList()
        {
            var path = BuildAclPath("binding-rules");
            return await ApiSend<List<ResultBindingRule>>(path);
        }
        #endregion
    }
}
